import Dep from './dep.js'
import { obserer } from './init.js'
import { arrayMethods } from './Array.js'
const hasProto = '__proto__' in {}
export function def (obj, key, val, enumerable) {
  Object.defineProperty(obj, key, {
    value: val,
    enumerable: !!enumerable,
    writable: true,
    configurable: true
  })
}
export class Observer {
  constructor (value) {
    this.value = value
    this.dep = new Dep() //数组的dep保存在Observer的实例上 数组在getter中收集依赖在拦截器中触发ilai 之所以保存在Observer实例上 是一位在getter中可以访问到Observer实例
    def(value, '__ob__', this) // 新增
    // 判断是数组还是对象
    // walk会将每一个属性都转换成getter/setter的形式来侦测变化
    if (Array.isArray(value)) {
      const augment = hasProto ? protoAugment : copyAugment
      augment(value, arrayMethods, arrayKeys)
      this.observeArray(value) // 将数组中的所有元素都转化位可被侦测的响应式
    } else {
      this.walk(value)
    }
  }
  observeArray (items) {
    for (let i = 0, len = items.length; i < len; i++) {
      observe(items[i])
    }
  }
  walk (obj) {
    //Object.keys 遍历对象上的属性(可枚举的)
    const keys = Object.keys(obj)
    for (let i = 0, len = keys.length; i < len; i++) {
      defineReactive(obj, keys[i], obj[keys[i]])
    }
  }
}

function protoAugment (target, src, keys) {
  target.__proto__ = src
}
/**
 * 当浏览器不支持__proto__的时候调用copyAugment
 * 函数将拦截器中的方法挂载到value上
 * @param {*} target 
 * @param {*} src 
 * @param {*} keys 
 */
function copyAugment (target, src, keys) {
  for (let i = 0, len = keys.length; i < len; i++) {
    const key = keys[i]
    def(target, key, src[key])
  }
}